package org.dandelion.papercheck.service.impl;

import org.dandelion.papercheck.dao.ArticleDao;
import org.dandelion.papercheck.dao.HistoryDao;
import org.dandelion.papercheck.dao.UserDao;
import org.dandelion.papercheck.dto.HistoryDetailDTO;
import org.dandelion.papercheck.entity.Article;
import org.dandelion.papercheck.entity.History;
import org.dandelion.papercheck.entity.HistoryItem;
import org.dandelion.papercheck.entity.User;
import org.dandelion.papercheck.service.HistoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

@Service
@Transactional
public class HistoryServiceImp implements HistoryService {
    private final UserDao userDao;
    private final HistoryDao historyDao;
    private final ArticleDao articleDao;

    @Autowired
    public HistoryServiceImp(UserDao userDao, HistoryDao historyDao, ArticleDao articleDao) {
        this.userDao = userDao;
        this.historyDao = historyDao;
        this.articleDao = articleDao;
    }

    @Override
    public List<History> getHistory(Long userId, Integer size, Integer page) {
        Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createDateTime");
        List<History> histories = new ArrayList<>();
        Optional<User> userOpt = userDao.findById(userId);

        if (userOpt.isEmpty()) {
            return histories;
        } else {
            histories = historyDao.findByUser(userOpt.get(), pageable);
        }
        return histories;
    }

    @Override
    public void createHistory(LocalDateTime dateTime, String username, String articleFileName,
                              Map<String, Double> articleSimilarMap) {
        var userList = userDao.findByUsername(username);

        if (userList.isEmpty()) {
            throw new RuntimeException("no such user: " + username);
        }

        var articleList = articleDao.findByFileName(articleFileName);

        if (articleList.isEmpty()) {
            throw new RuntimeException("no such article: " + articleFileName);
        }

        var user = userList.get(0);
        var article = articleList.get(0);
        var history = new History();

        history.setArticle(article);
        history.setUser(user);
        history.setCreateDateTime(dateTime);

        var historyItems = new ArrayList<HistoryItem>();

        for (var entry : articleSimilarMap.entrySet()) {
            Article at = articleDao.findByFileName(entry.getKey()).get(0);
            Double similar = entry.getValue();
            var historyItem = new HistoryItem();

            historyItem.setHistory(history);
            historyItem.setArticle(at);

            historyItem.setSimilarity(similar);
            historyItems.add(historyItem);
        }

        history.setHistoryItems(historyItems);

        historyDao.save(history);
    }

    public List<HistoryDetailDTO> getDetail(Long historyId) {
        Optional<History> historyOpt = historyDao.findById(historyId);

        if (historyOpt.isEmpty()) {
            return null;
        }
        History history = historyOpt.get();

        var items = history.getHistoryItems();
        var ret = new ArrayList<HistoryDetailDTO>();

        for (var item : items) {
            var dto = new HistoryDetailDTO();
            dto.setFileName(item.getArticle().getFileName());
            dto.setSimilarity(item.getSimilarity());
            ret.add(dto);
        }

        return ret;
    }
}
